by Michael Morrison
In This Chapter
Youve learned a fair amount about user interfaces up to this point in the book. However, you havent really looked into how to extend user interfaces and support modern features such as floating pop-up menus, control bars, and wizards. Users have come to expect flexible and intuitive user interfaces, and its your job to give them what they want. Fortunately, MFC includes plenty of support for building rich user interfaces without too much suffering on the part of the MFC programmer.
Indeed, supporting modern user interface features in your own applications is very straightforward thanks to MFC. This chapter shows you how to extend user interfaces and examines the MFC classes that make it possible to support these types of features.
Before you get into the different ways to extend user interfaces with GUI elements, lets take a moment to examine user input and how it is handled with MFC. This is important because you can greatly improve the feel of an application simply through the handling of the keyboard and mouse. Keyboard and mouse handling begins with a special set of messages that are sent when the user presses or releases a key on the keyboard, moves the mouse, or clicks a mouse button.
Handling keyboard and mouse messages is as simple as determining the specific messages you want to handle and then creating the appropriate message handlers for them. Win32 supports a variety of different keyboard and mouse messages, so its important to make sure you are handling the proper messages to achieve your desired functionality.
When you press a key in a Windows application, Windows generates a keyboard message. This message is sent to the application whose main frame window has keyboard focus. The application then handles the message and does whatever it needs to do with the keystroke information. In the case of a word processor, the application might store away a character based on the key press and draw the character on the screen.
Because internationalized applications must be capable of handling multiple languages, keyboard messages arent directly associated with specific characters on the keyboard. Instead, the Win32 API defines virtual key codes that are mapped to each key on the keyboard. Virtual key codes serve as device-independent identifiers for keys on the keyboard. Applications always interpret keystrokes as virtual key codes instead of raw characters. Following are some examples of virtual key codes defined in the Win32 API:
The routing of keyboard messages is based on which window has keyboard focus, which is a specific type of input focus. Input focus is a temporary property that only one window at a time is capable of having. Input focus is associated with the currently active window, which is often identifiable by a highlighted caption bar, dialog frame, or caption text, depending on the type of window. Although input focus plays an important role in determining where keyboard messages are sent, it doesnt tell the whole story.
Keyboard focus determines when a window actually receives keyboard messages. Keyboard focus is a more specific type of input focus that requires that a window not be minimized. For example, a minimized word processor shouldnt accept keyboard input because you cant see what youre typing. Minimized applications dont receive keyboard messages because they dont have keyboard focus.
Each time you press and release a key in Windows, a keyboard message is generated. In fact, an individual message is generated both for the key press and the key release. Table 8.1 lists the Win32 messages associated with keystrokes, along with the MFC message handlers for each.
| Message | Message Handler |
|---|---|
| WM_KEYDOWN | OnKeyDown() |
| WM_KEYUP | OnKeyUp() |
| WM_CHAR | OnChar() |
| WM_SYSKEYDOWN | OnSysKeyDown() |
| WM_SYSKEYUP | OnSysKeyUp() |
The WM_KEYDOWN and WM_KEYUP messages are used to process the vast majority of keystrokes. The WM_CHAR message is similar to the WM_KEYDOWN message, except it contains a translated character associated with the key press. The WM_CHAR message is sent after a WM_KEYDOWN and WM_KEYUP message combination. The WM_SYSKEYDOWN and WM_SYSKEYUP messages are sent in response to system keystrokes such as key combinations involving the Alt key. All the keyboard messages except WM_CHAR are sent in key down/key up pairs. However, when a key is held down and the typematic repeat for the keyboard kicks in, Windows sends a series of key down messages followed by a single key up message when the key is released.
Note:Windows automatically handles system keystrokes such as using the Alt key to access menus. It is rare that you would want to handle system keystrokes in an application. Windows also automatically handles keyboard accelerators, which are used as shortcuts to invoke some menu commands.
The OnKeyDown() message handler is relatively straightforwardit accepts a few parameters that contain information about the key press. Its declaration follows:
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
All the keyboard message handlers accept these same parameters. The nChar parameter specifies the virtual-key code of the key being pressed. The nRepCnt parameter specifies the repeat count, which applies if a key is being held down and the typematic repeat function of the keyboard is invoked. Finally, the nFlags parameter specifies additional information such as whether the Alt key was down when the key was pressed.
To handle keyboard messages, you must add a message map entry for each message handler you want to use. For example, the following message map entry is required to handle the WM_KEYDOWN message using the OnKeyDown() message handler:
ON_WM_KEYDOWN()
One interesting way to experiment with handling keyboard messages is to move the mouse cursor in response to the user pressing the arrow keys on the keyboard. The OnKeyDown() message handler is the only one you need to implement to carry out this functionality. Listing 8.1 contains the source code for an OnKeyDown() message handler that moves the mouse cursor in response to the user pressing the arrow keys.